﻿using Devonline.Communication.Messages;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Devonline.Identity.Admin.Controllers;

[Route("api/[controller]")]
[ApiController]
[SecurityHeaders]
[Authorize(Roles = GROUP_MAINTAINERS)]
public class AccessRulesController : ODataModelServiceController<AccessRule, AccessRuleViewModel>
{
    private readonly IDataService<User> _userService;
    private readonly AuthorizationService _authorizationService;
    private readonly IMessageCommunicator _communicator;
    public AccessRulesController(
        AuthorizationService authorizationService,
        ILogger<AccessRulesController> logger,
        IMessageCommunicator communicator,
        IDataService<AccessRule> dataService,
        IDataService<User> userService
        ) : base(logger, dataService)
    {
        _userService = userService;
        _authorizationService = authorizationService;
        _communicator = communicator;
        //_dataService.Notice += async (sender, message) => await _communicator.RefreshCacheAsync(message.Content);
    }

    [HttpPost]
    public override async Task<IActionResult> CreateAsync(AccessRuleViewModel viewModel)
    {
        if (viewModel.IdentityType == IdentityType.All)
        {
            viewModel.IdentityId = null;
        }

        if (viewModel.IdentityType == IdentityType.Anonymous || viewModel.IdentityType == IdentityType.System)
        {
            viewModel.IdentityId = _userService.GetQueryable(x => x.UserName == viewModel.IdentityType.ToString().ToLowerInvariant()).Select(x => x.Id).FirstOrDefault();
        }

        await _dataService.AddAsync(viewModel);
        await RefreshUserInfo(viewModel.IdentityType, viewModel.IdentityId);
        return Ok(viewModel);
    }

    [HttpPut]
    public override async Task<IActionResult> UpdateAsync(AccessRuleViewModel viewModel)
    {
        if (viewModel.IdentityType == IdentityType.All)
        {
            viewModel.IdentityId = null;
        }

        if (viewModel.IdentityType == IdentityType.Anonymous || viewModel.IdentityType == IdentityType.System)
        {
            viewModel.IdentityId = _userService.GetQueryable(x => x.UserName == viewModel.IdentityType.ToString().ToLowerInvariant()).Select(x => x.Id).FirstOrDefault();
        }

        await _dataService.UpdateAsync(viewModel);
        await RefreshUserInfo(viewModel.IdentityType, viewModel.IdentityId);
        return Ok(viewModel);
    }

    [HttpDelete("{id}")]
    public override async Task<IActionResult> DeleteAsync(string id)
    {
        var entitySet = await _dataService.GetIfExistAsync(id);
        await _dataService.DeleteAsync(id);
        await RefreshUserInfo(entitySet.IdentityType, entitySet.IdentityId);
        return Ok();
    }

    /// <summary>
    /// 此处的获取用户信息会自动刷新缓存
    /// </summary>
    /// <param name="userName"></param>
    /// <param name="system"></param>
    /// <returns></returns>
    [HttpGet("GetUserInfo")]
    public async Task<IActionResult> GetUserInfoAsync(string userName, string? system = default)
    {
        var userContext = await _authorizationService.GetUserContextAsync(userName, true);
        if (userContext is null)
        {
            return NotFound();
        }

        return Ok(new UserInfo
        {
            User = userContext.User,
            Resources = string.IsNullOrWhiteSpace(system) ? userContext.Resources : userContext.Resources.Where(x => x.ResourceType == ResourceType.Page && x.Content != null && x.Content.StartsWith(system)).ToList(),
            ResourceTree = string.IsNullOrWhiteSpace(system) ? userContext.ResourceTree : userContext.ResourceTree.Where(x => x.Content != null && x.Content.StartsWith(system)).ToList()
        });
    }

    [HttpGet("UserHasPermission/{userName}")]
    public async Task<IActionResult> UserHasPermissionAsync(string userName, string resource) => Ok(await _authorizationService.UserHasPermissionAsync(resource, userName));

    /// <summary>
    /// 刷新用户授权相关缓存
    /// </summary>
    /// <returns></returns>
    private async Task RefreshUserInfo(IdentityType identityType, string? id = null)
    {
        if (id is not null)
        {
            var users = await _authorizationService.GetIdentityUsers(identityType, id);
            if (users is not null && users.Any())
            {
                foreach (var user in users)
                {
                    //更新用户授权相关缓存
                    await _authorizationService.GetUserContextAsync(user.UserName, true);

                    //强制推送客户端更新
                    await _communicator.SendAsync(Constants.CACHE_USER_INFO, user.UserName, MessageType.Cache);
                }
            }
        }
    }
}